<?php

class UserManager
{
	private $_db;
	
	public function __construct(PDO $db)
	{
		$this->setDb($db);
	}
	
	public function setDb($db)
	{
		$this->_db = $db;
	}
	
	public function add(User $user)
	{
		//Fonction qui va ajouter un user dans la table users
		$reqInsert = $this->_db->prepare("INSERT INTO users SET login= :login, password= :password, gender= :gender, firstName= :firstName, lastName= :lastName, mail= :mail, tel= :tel");
		$reqInsert->bindValue(":login", $user->login());
		$reqInsert->bindValue(":password", $user->password());
		$reqInsert->bindValue(":gender", $user->gender());
		$reqInsert->bindValue(":firstName", $user->firstName());
		$reqInsert->bindValue(":lastName", $user->lastName());
		$reqInsert->bindValue(":mail", $user->mail());
		$reqInsert->bindValue(":tel", $user->tel());
		$reqInsert->execute();
		$user->hydrate(array(
			'id' => $this->_db->lastInsertId()
		));
	}
	public function delete(User $user)
	{
		//Fonction qui va supprimer un user dans la table users
		$reqDelete = $this->_db->prepare("DELETE FROM users WHERE id= :id");
		$reqDelete->bindValue(":id", $user->id());
		$reqDelete->execute();
	}
	public function update(User $user)
	{
		//Fonction qui va mettre à jour un user dans la table users
		$reqUpdate = $this->_db->prepare("UPDATE users SET login= :login, password= :password, gender= :gender, firstName= :firstName, lastName= :lastName, mail= :mail, tel= :tel WHERE id= :id");
		$reqUpdate->bindValue(":id", $user->id(), PDO::PARAM_INT);
		$reqUpdate->bindValue(":login", $user->login(), PDO::PARAM_STR);
		$reqUpdate->bindValue(":password", $user->password(), PDO::PARAM_STR);
		$reqUpdate->bindValue(":gender", $user->gender(), PDO::PARAM_STR);
		$reqUpdate->bindValue(":firstName", $user->firstName(), PDO::PARAM_STR);
		$reqUpdate->bindValue(":lastName", $user->lastName(), PDO::PARAM_STR);
		$reqUpdate->bindValue(":mail", $user->mail(), PDO::PARAM_STR);
		$reqUpdate->bindValue(":tel", $user->tel(), PDO::PARAM_STR);
		$reqUpdate->execute();
	}
	
	public function getLast()
	{
		//Fonction qui ramène le dernier user créé = celui avec l'id le plus grand
		$reqSelect = $this->_db->prepare("SELECT * FROM users WHERE id= :id");
		$id = $this->_db->lastInsertId();
		$reqSelect->bindValue(":id", $id);
		$reqSelect->execute();
		$user = $reqSelect->fetch(PDO::FETCH_ASSOC);
		return new User($user);
	}
	
	public function get($search)
	{
		//Fonction qui va chercher un user dans la table users à partir du critère de recherche search, ou une liste de users si critère de recherche basé sur le login ou le mail
		if(is_int($search))
		{
			$reqSelect = $this->_db->prepare("SELECT * FROM users WHERE id= :id");
			$reqSelect->bindValue(":id", $search);
			$reqSelect->execute();
			$user = $reqSelect->fetch(PDO::FETCH_ASSOC);
			return new User($user);
		}
		if(is_string($search))
		{
			$users = array();
			$reqSelect = $this->_db->prepare("SELECT * FROM users WHERE login LIKE :login OR mail LIKE :mail");
			$reqSelect->bindValue(":login", '%'.$search.'%');
			$reqSelect->bindValue(":mail", '%'.$search.'%');
			$reqSelect->execute();
			while($user = $reqSelect->fetch(PDO::FETCH_ASSOC))
			{
				$userL = new User($user);
				$users[] = $userL;
			}
			$reqSelect->closeCursor();
			return $users;
		}
	}
	public function exist($search)
	{
		//Fonction qui vérifie l'existence d'un user dans la table users
		if(is_int($search))
		{
			$reqSelect = $this->_db->prepare("SELECT * FROM users WHERE id= :id");
			$reqSelect->bindValue(":id", $search);
			$reqSelect->execute();
			return (bool) $reqSelect->fetch();
		}
		if(is_string($search))
		{
			$reqSelect = $this->_db->prepare("SELECT * FROM users WHERE login= :login OR mail= :mail");
			$reqSelect->bindValue(":login", $search);
			$reqSelect->bindValue(":mail", $search);
			$reqSelect->execute();
			return (bool) $reqSelect->fetch();
		}
	}
	public function getList()
	{
		//Fonction qui retourne la liste des users possédant un compte
		$users = array();
		$reqListe = $this->_db->query("SELECT * FROM users");
		while($user = $reqListe->fetch(PDO::FETCH_ASSOC))
		{
			$userL = new User($user);
			$users[] = $userL;
		}
		$reqListe->closeCursor();
		return $users;
	}
	
	public function isAdmin(User $user, Contest $contest)
	{
		//Fonction qui dit si user est admin ou non du contest
		$req = $this->_db->query("SELECT admin FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$admin = $req->fetch(PDO::FETCH_ASSOC);
		return $admin['admin'];
	}
	public function isCreator(User $user, Contest $contest)
	{
		//Fonction qui dit si user est créateur ou non du contest
		$req = $this->_db->query("SELECT creator FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$creator = $req->fetch(PDO::FETCH_ASSOC);
		return $creator['creator'];
	}
	public function getStatusPlayer(User $user, Contest $contest)
	{
		//Fonction qui donne le statut de participation de user au contest
		$req = $this->_db->query("SELECT statusParticipation_id FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$status = $req->fetch(PDO::FETCH_ASSOC);
		$statusParticipationManager = new StatusParticipationManager($this->_db);
		if(is_array($status) && $status['statusParticipation_id']!=null) return array((int) $status['statusParticipation_id'], $statusParticipationManager->get((int) $status['statusParticipation_id'])->name());
		else return array(0, "Non-inscrit");
		return 0;
	}
	public function invited(User $user, Contest $contest)
	{
		//Fonction qui dit par qui un user a été invité à un concours et quand, s'il a été invité
		$req = $this->_db->query("SELECT invitedBy, dateInvitation FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$invited = $req->fetch(PDO::FETCH_ASSOC);
		if($invited['invitedBy']==0) return null;
		return $invited;
	}
	public function requested(User $user, Contest $contest)
	{
		//Fonction qui dit à quelle date la demande d'inscription a été effectuée au contest, si elle a été faite
		$req = $this->_db->query("SELECT dateRequest FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$date = $req->fetch(PDO::FETCH_ASSOC);
		if($date['dateRequest']=='0000-00-00') return null;
		return $date['dateRequest'];
	}
	public function plays(User $user, Contest $contest)
	{
		//Fonction qui dit depuis quelle date la participation au concours est effective
		$req = $this->_db->query("SELECT dateParticipation FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$date = $req->fetch(PDO::FETCH_ASSOC);
		if($date['dateParticipation']=='0000-00-00') return null;
		return $date['dateParticipation'];
	}
	public function banned(User $user, Contest $contest)
	{
		//Fonction qui dit à quelle date le joueur a été banni
		if($this->getStatusPlayer($user, $contest) != 4) return null;
		$req = $this->_db->query("SELECT dateBan FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$date = $req->fetch(PDO::FETCH_ASSOC);
		return $date['dateBan'];
	}
	public function refusedInvitation(User $user, Contest $contest)
	{
		//Fonction qui dit à quelle date le joueur a refusé l'invitation
		if($this->getStatusPlayer($user, $contest) != 6) return null;
		$req = $this->_db->query("SELECT dateRefusedInvitation FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$date = $req->fetch(PDO::FETCH_ASSOC);
		return $date['dateRefusedInvitation'];
	}
	public function refusedRequestByAdmin(User $user, Contest $contest)
	{
		//Fonction qui dit à quelle date l'admin a refusé la demande de participation du joueur
		if($this->getStatusPlayer($user, $contest) != 5) return null;
		$req = $this->_db->query("SELECT dateParticipationDeclined FROM players WHERE contest_id=".$contest->id()." AND user_id = ".$user->id()."");
		$date = $req->fetch(PDO::FETCH_ASSOC);
		return $date['dateParticipationDeclined'];
	}
	
	public function inviteKilbet(User $userInviting, $mailInvited)
	{
		//Fonction qui permet à un utilisateur d'inviter une personne à rejoindre la communauté Kilbet : envoi d'un email avec lien vers le formulaire de création de compte
		
			//Vérification que mailInvited correspond bien à une adresse mail
		$regex_mail="#^[-.\w]+@[-.\w]{2,}\.[\D]{2,4}$#";
		if($mailInvited!="" && !preg_match($regex_mail, $mailInvited))
		{
			return 0;
		}
	
		$messageFrom = $userInviting->id();
		$mailFrom = $userInviting->mail();
		$mailTo = $mailInvited;
		$subject = html_entity_decode($userInviting->firstName()).' '.html_entity_decode($userInviting->lastName()).' vous invite à rejoindre Kilbet';
	
		if(Config::$ENV == "DEV")
		{
			$urlCreate='http://localhost/kilbet/create_account.php?action=create&from=mail';
		}
		elseif(Config::$ENV == "PROD")
		{
			$urlCreate='http://www.kildev.fr/create_account.php?action=create&from=mail';
		}

		$text = '
			<html>
				<head>
					<title>Invitation à rejoindre la communauté Kilbet</title>
				</head>
				<body>
					<p>Bonjour,</p>
					<p>'.$userInviting->firstName().' '.$userInviting->lastName().' ('.$userInviting->login().') vous invite à rejoindre la communauté Kilbet, en cliquant <a href="'.$urlCreate.'" alt="Créer un compte Kilbet">ici</a>.</p>
					<p>Habitué des concours de pronostics entre amis sur des fichiers excel ? Habitué également aux difficultés liées à la gestion et l\'animation de ces concours ?<br />
					Kilbet est la 1ère plateforme à vous apporter une solution !!</p>
					<p>Bonne chance,<br />
					L\'équipe Kilbet</p>
				</body>
			</html>
		';
		$messageManager = new MessageManager($this->_db);
		$messageManager->add(new Message(array(
			'contest_id' => 0,
			'messageFrom' => $messageFrom,
			'mailFrom' => $mailFrom,
			'messageTo' => '',
			'mailTo' => $mailTo,
			'subject' => $subject,
			'text' => $text,
			'sendMail' => 1,
			'category_id' => 2
		)));
		return 1;
	}
	public function inviteContest(User $userInviting, User $userInvited, Contest $contest)
	{
		//Fonction qui permet à userInviting d'inviter userInvited au contest : ajout du userInvited dans la table players avec le statut 3 + envoi par mail d'une notif d'invitation au concours
			
			//MàJ BDD
		$req = $this->_db->prepare("INSERT INTO players SET user_id= :user_id, contest_id= :contest_id, admin=0, creator=0, statusParticipation_id= 2, invitedBy= :user_id2, dateInvitation= NOW()");
		$req->bindValue(":user_id", $userInvited->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->bindValue(":user_id2", $userInviting->id());
		$req->execute();
		
			//Envoi message
		$contest_id = $contest->id();
		$messageFrom = $userInviting->id();
		$mailFrom = $userInviting->mail();
		$messageTo = $userInvited->id();
		$mailTo = $userInvited->mail();
		$subject = "Kilbet - Invitation à participer à un concours";
		$sendMail = 1;
		$category_id = 2;
	
		if(Config::$ENV == "DEV")
		{
			$urlAccept='http://localhost/kilbet/contest.php?contestid='.$contest->id().'&action=accept&from=mail';
			$urlDecline='http://localhost/kilbet/contest.php?contestid='.$contest->id().'&action=refuse&from=mail';
			$urlCheck='http://localhost/kilbet/contest.php?contestid='.$contest->id().'&from=mail';
		}
		elseif(Config::$ENV == "PROD")
		{
			$urlAccept='http://www.kildev.fr/contest.php?contestid='.$contest->id().'&action=accept&from=mail';
			$urlDecline='http://www.kildev.fr/contest.php?contestid='.$contest->id().'&action=refuse&from=mail';
			$urlCheck='http://www.kildev.fr/contest.php?contestid='.$contest->id().'&from=mail';
		}

		$text = '
			<html>
				<head>
					<title>Invitation à participer à un concours Kilbet</title>
				</head>
				<body>
					<p>Bonjour '.$userInvited->login().',</p>
					<p>'.$userInviting->login().' vous a invité à participer au concours '.$contest->name().'. Vous pouvez <a href="'.$urlAccept.'" alt="Accepter l\'invitation">accepter</a> ou <a href="'.$urlDecline.'">refuser</a> cette invitation, ou vous rendre sur la page du concours en cliquant <a href="'.$urlCheck.'">ici</a> pour voir les détails de ce concours.</p>
					<p>Bonne chance,<br />
					L\'équipe Kilbet</p>
				</body>
			</html>
		';
		$messageManager = new MessageManager($this->_db);
		$messageManager->add(new Message(array(
			'contest_id' => $contest_id,
			'responseMessage_id' => 0,
			'messageFrom' => $messageFrom,
			'mailFrom' => $mailFrom,
			'messageTo' => 'u'.$messageTo.';',
			'mailTo' => $mailTo,
			'subject' => $subject,
			'text' => $text,
			'sendMail' => $sendMail,
			'category_id' => $category_id
		)));
	}
	public function requestContest(User $user, Contest $contest)
	{
		//Fonction qui permet au user de demander l'inscription au contest :
			//si concours privé : ajout du user dans la table players avec le statut 3 => attente d'approbation par admin
			//si concours public : ajout du user dans la table players avec le statut 1 => pas d'approbation nécessaire
		if($contest->privateE() == 0) $req = $this->_db->prepare("INSERT INTO players SET user_id= :user_id, contest_id= :contest_id, admin=0, creator=0, statusParticipation_id= 1, dateRequest= NOW(), dateParticipation= NOW()");
		elseif($contest->privateE() == 1) $req = $this->_db->prepare("INSERT INTO players SET user_id= :user_id, contest_id= :contest_id, admin=0, creator=0, statusParticipation_id= 3, dateRequest= NOW()");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	public function acceptInvitationContest(User $user, Contest $contest)
	{
		//Fonction qui permet au user d'accepter une invitation à un contest, reste à avoir l'approbation d'un admin : update du user dans la table players avec le statut 3
			//Cas particulier si l'invitation est pour un évènement public : pas besoin d'approbation supplémentaire par un admin
		if($contest->privateE() == 1) 
		{
			//Cas particulier si l'invitation vient d'un admin : pas besoin d'approbation non plus
			if(!$this->isAdmin($this->get((int) $this->invited($user, $contest)['invitedBy']), $contest)) $req = $this->_db->prepare("UPDATE players SET statusParticipation_id= 3, dateRequest= NOW() WHERE user_id= :user_id AND contest_id= :contest_id");
			else $req = $this->_db->prepare("UPDATE players SET statusParticipation_id= 1, dateRequest= NOW() WHERE user_id= :user_id AND contest_id= :contest_id");
		}
		else $req = $this->_db->prepare("UPDATE players SET statusParticipation_id= 1, dateParticipation= NOW() WHERE user_id= :user_id AND contest_id= :contest_id");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	public function declineInvitationContest(User $user, Contest $contest)
	{
		//Fonction qui permet au user de refuser une invitation à un contest : update du user dans la table players avec le statut 6
		$req = $this->_db->prepare("UPDATE players SET statusParticipation_id= 6, dateRefusedInvitation= NOW() WHERE user_id= :user_id AND contest_id= :contest_id");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	
	public function acceptRequestContest(User $admin, User $user, Contest $contest)
	{
		//Fonction qui permet à un admin de valider la demande d'inscription de user à un concours : update du user dans la table players avec le statut 1
		if(!$this->isAdmin($admin, $contest)) return;
		$req = $this->_db->prepare("UPDATE players SET statusParticipation_id= 1, dateParticipation= NOW() WHERE user_id= :user_id AND contest_id= :contest_id");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	public function declineRequestContest(User $admin, User $user, Contest $contest)
	{
		//Fonction qui permet à un admin de refuser la demande d'inscription de user à un concours : update du user dans la table players avec le statut 5
		if(!$this->isAdmin($admin, $contest)) return;
		$req = $this->_db->prepare("UPDATE players SET statusParticipation_id= 5, dateParticipationDeclined= NOW() WHERE user_id= :user_id AND contest_id= :contest_id");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	public function banFromContest(User $admin, User $user, Contest $contest)
	{
		//Fonction qui permet à un admin de bannir user du concours : update du user dans la table players avec le statut 4
		if(!$this->isAdmin($admin, $contest)) return;
		$req = $this->_db->prepare("UPDATE players SET statusParticipation_id= 4, dateBan=NOW() WHERE user_id= :user_id AND contest_id= :contest_id");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	public function promoteAsAdmin(User $admin, User $user, Contest $contest)
	{
		//Fonction qui permet à un admin de promouvoir un user au rang d'admin du concours, fonctionnalité accessible uniquement au créateur du concours : update du user dans la table players avec admin = 1
		if(!$this->isCreator($admin, $contest)) return;
		$req = $this->_db->prepare("UPDATE players SET admin=1 WHERE user_id= :user_id AND contest_id= :contest_id");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	public function demoteAdmin(User $admin, User $user, Contest $contest)
	{
		//Fonction qui permet à un admin de rétrograder un admin au rang de joueur du concours, fonctionnalité accessible uniquement au créateur du concours : update du user dans la table players avec admin = 0
		if(!$this->isCreator($admin, $contest) || $this->isCreator($user, $contest)) return;
		$req = $this->_db->prepare("UPDATE players SET admin=0 WHERE user_id= :user_id AND contest_id= :contest_id");
		$req->bindValue(":user_id", $user->id());
		$req->bindValue(":contest_id", $contest->id());
		$req->execute();
	}
	
	public function getListContests(User $user, $status)
	{
		//Fonction qui ramène la liste des concours suivant son statut de participation (variable status). Si status = -1 : on ramène tous les concours avec lesquels le user n'a aucune interaction (pas inscrit, pas invité, ...). Si status = 0 : on ramène tous les concours avec lesquels le user a une interaction
		$contests = array();
		if($status==-1) $reqList = $this->_db->query("SELECT * FROM contests WHERE id NOT IN(SELECT contest_id FROM players WHERE user_id = ".$user->id().")");
		elseif($status==0) $reqList = $this->_db->query("SELECT * FROM contests WHERE id IN(SELECT contest_id FROM players WHERE user_id = ".$user->id().")");
		else $reqList = $this->_db->query("SELECT * FROM contests WHERE id IN(SELECT contest_id FROM players WHERE user_id = ".$user->id()." AND statusParticipation_id = ".$status.")");
		while($contest = $reqList->fetch(PDO::FETCH_ASSOC))
		{
			$contestL = new Contest($contest);
			$contests[] = $contestL;
		}
		$reqList->closeCursor();
		return $contests;
	}
	
	public function getListMessagesReceivedInbox(User $user)
	{
		//Fonction qui ramène la liste des messages reçus par le user et présents dans son inbox
		$messages = array();
		$reqList = $this->_db->query("SELECT t1.*, t2.id FROM messages t1, users t2 WHERE t1.messageTo LIKE CONCAT('u',t2.id,';') AND t2.id = ".$user->id()." AND t1.inInbox = 1");
		while($message = $reqList->fetch(PDO::FETCH_ASSOC))
		{
			$messageL = new Message($message);
			$messages[] = $messageL;
		}
		$reqList->closeCursor();
		return $messages;
	}
	public function getListMessagesSentInbox(User $user)
	{
		//Fonction qui ramène la liste des messages envoyés par le user et présents dans son inbox
		$messages = array();
		$reqList = $this->_db->query("SELECT * FROM messages WHERE messageFrom IN(SELECT id FROM users WHERE id = ".$user->id()." AND inInbox = 1)");
		while($message = $reqList->fetch(PDO::FETCH_ASSOC))
		{
			$messageL = new Message($message);
			$messages[] = $messageL;
		}
		$reqList->closeCursor();
		return $messages;
	}
}